namespace Angelus.Data.Linq.ProviderBase
{
	using System;
    using System.Collections.Generic;
    using System.Data.DLinq.ProviderBase;

    /// <summary>
    /// 
    /// </summary>
    internal class OracleCompletingRowReader : RowReader, IDisposable, IConnectionUser
    {
        #region Fields

        private readonly IConnectionManager _connectionManager;
        private List<CompletingFieldReader> _readers;
        private RowReader _reader;

        #endregion

        #region Constructors

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connectionManager"></param>
        /// <param name="reader"></param>
        internal OracleCompletingRowReader(IConnectionManager connectionManager, RowReader reader)
        {
            if (connectionManager == null)
            {
                throw new ArgumentNullException("connectionManager");
            }
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            this._connectionManager = connectionManager;
            this._reader = reader;
        }

        #endregion

        #region Disposable Implementation

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            IDisposable disposable = this._reader as IDisposable;
            if (null != disposable)
            {
                disposable.Dispose();
            }
            this._reader = null;
            this._connectionManager.ReleaseConnection(this);
        }

        #endregion

        #region Properties

        /// <summary>
        /// 
        /// </summary>
        internal bool IsBuffered
        {
            get { return (this._reader is BufferedRowReader); }
        }

        #endregion

        #region Reading

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        internal override object GetBoxedValue(int index)
        {
            return this._reader.GetBoxedValue(index);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        internal override int GetFieldIndex(string name)
        {
            return this._reader.GetFieldIndex(name);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        internal override RowFieldReader<T> GetFieldReader<T>()
        {
            CompletingFieldReader<T> reader = new CompletingFieldReader<T>(this._reader.GetFieldReader<T>());
            if (null == this._readers)
            {
                this._readers = new List<CompletingFieldReader>();
            }
            this._readers.Add(reader);
            return reader.Read;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        internal override bool NextResult()
        {
            return this._reader.NextResult();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        internal override bool Read()
        {
            if (null == this._reader)
            {
                throw new Exception("Reader disposed");
            }
            return this._reader.Read();
        }

        #endregion

        #region ConnectionUser Implemenation

        /// <summary>
        /// 
        /// </summary>
        void IConnectionUser.CompleteUse()
        {
            DataRowReader reader = this._reader as DataRowReader;
            if (null != reader)
            {
                this._reader = reader.GetBufferedReader();
                if (null != this._readers)
                {
                    List<CompletingFieldReader>.Enumerator enumerator = this._readers.GetEnumerator();
                    try
                    {
                        while (enumerator.MoveNext())
                        {
                            enumerator.Current.Reset(this._reader);
                        }
                    }
                    finally
                    {
                        enumerator.Dispose();
                    }
                }
            }
            this._connectionManager.ReleaseConnection(this);
        }

        #endregion

        #region Nested classes

        /// <summary>
        /// 
        /// </summary>
        internal abstract class CompletingFieldReader
        {
            #region Reader Implementation

            /// <summary>
            /// 
            /// </summary>
            /// <param name="reader"></param>
            internal abstract void Reset(RowReader reader);

            #endregion
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        internal class CompletingFieldReader<T> : CompletingFieldReader
        {
            #region Fields

            private RowFieldReader<T> _reader;

            #endregion

            #region Constructors

            /// <summary>
            /// 
            /// </summary>
            /// <param name="reader"></param>
            internal CompletingFieldReader(RowFieldReader<T> reader)
            {
                this._reader = reader;
            }

            #endregion

            #region Reader Implementation

            /// <summary>
            /// 
            /// </summary>
            /// <param name="index"></param>
            /// <returns></returns>
            internal T Read(int index)
            {
                try
                {
                    return this._reader(index);
                }
                catch (Exception)
                {
                }
                return default(T);
            }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="reader"></param>
            internal override void Reset(RowReader reader)
            {
                this._reader = reader.GetFieldReader<T>();
            }

            #endregion
        }

        #endregion
    }
}